<?php

namespace app\common\library;

use think\Db;

/**
 * 教学点经纬度获取助手类
 * 提供教学点经纬度的回退逻辑处理
 */
class OcationCoordinateHelper
{
    /**
     * 获取教学点经纬度和地址（带回退逻辑）
     * 优先级：主教学点 → 子教学点 → 父教学点
     *
     * @param int $ocationId 教学点ID
     * @return array ['longitude' => float|null, 'latitude' => float|null, 'address' => string|null, 'source' => string]
     */
    public static function getCoordinates($ocationId)
    {
        if (!$ocationId) {
            return [
                'longitude' => null,
                'latitude' => null,
                'address' => null,
                'source' => 'none'
            ];
        }

        // 获取主教学点信息
        $mainOcation = Db::name('ocation')->where('id', $ocationId)->find();
        if (!$mainOcation) {
            return [
                'longitude' => null,
                'latitude' => null,
                'address' => null,
                'source' => 'not_found'
            ];
        }

        // 检查主教学点是否有有效经纬度
        if (self::isValidCoordinate($mainOcation['longitude'], $mainOcation['latitude'])) {
            $address = $mainOcation['address'] ?? '';

            // 如果地址为空，通过百度地图API获取
            if (empty($address)) {
                $addressResult = self::getAddressByCoordinates($mainOcation['longitude'], $mainOcation['latitude']);
                if ($addressResult['success'] && !empty($addressResult['data']['formatted_address'])) {
                    $address = $addressResult['data']['formatted_address'];

                    // 更新数据库中的地址
                    try {
                        Db::name('ocation')->where('id', $ocationId)->update([
                            'address' => $address,
                            'update_time' => time()
                        ]);
                    } catch (\Exception $e) {
                        // 数据库更新失败不影响返回结果
                    }
                }
            }

            return [
                'longitude' => (float)$mainOcation['longitude'],
                'latitude' => (float)$mainOcation['latitude'],
                'address' => $address,
                'source' => 'main'
            ];
        }

        // 主教学点没有经纬度，递归遍历所有子教学点（包括子教学点的子教学点）
        $validChildOcation = self::findValidChildOcation($ocationId);

        if ($validChildOcation) {
            $address = $validChildOcation['address'] ?? '';

            // 如果地址为空，通过百度地图API获取
            if (empty($address)) {
                $addressResult = self::getAddressByCoordinates($validChildOcation['longitude'], $validChildOcation['latitude']);
                if ($addressResult['success'] && !empty($addressResult['data']['formatted_address'])) {
                    $address = $addressResult['data']['formatted_address'];

                    // 更新数据库中的地址
                    try {
                        Db::name('ocation')->where('id', $validChildOcation['id'])->update([
                            'address' => $address,
                            'update_time' => time()
                        ]);
                    } catch (\Exception $e) {
                        // 数据库更新失败不影响返回结果
                    }
                }
            }

            return [
                'longitude' => (float)$validChildOcation['longitude'],
                'latitude' => (float)$validChildOcation['latitude'],
                'address' => $address,
                'source' => 'child'
            ];
        }

        // 子教学点也没有经纬度，尝试获取父教学点的经纬度
        if (!empty($mainOcation['pid']) && $mainOcation['pid'] > 0) {
            $parentOcation = Db::name('ocation')->where('id', $mainOcation['pid'])->find();
            if ($parentOcation && self::isValidCoordinate($parentOcation['longitude'], $parentOcation['latitude'])) {
                $address = $parentOcation['address'] ?? '';

                // 如果地址为空，通过百度地图API获取
                if (empty($address)) {
                    $addressResult = self::getAddressByCoordinates($parentOcation['longitude'], $parentOcation['latitude']);
                    if ($addressResult['success'] && !empty($addressResult['data']['formatted_address'])) {
                        $address = $addressResult['data']['formatted_address'];

                        // 更新数据库中的地址
                        try {
                            Db::name('ocation')->where('id', $parentOcation['id'])->update([
                                'address' => $address,
                                'update_time' => time()
                            ]);
                        } catch (\Exception $e) {
                            // 数据库更新失败不影响返回结果
                        }
                    }
                }

                return [
                    'longitude' => (float)$parentOcation['longitude'],
                    'latitude' => (float)$parentOcation['latitude'],
                    'address' => $address,
                    'source' => 'parent'
                ];
            }
        }

        // 都没有经纬度，返回空值
        return [
            'longitude' => null,
            'latitude' => null,
            'address' => null,
            'source' => 'empty'
        ];
    }

    /**
     * 批量获取多个教学点的经纬度
     * 
     * @param array $ocationIds 教学点ID数组
     * @return array 格式：[ocation_id => ['longitude' => float|null, 'latitude' => float|null, 'source' => string], ...]
     */
    public static function getBatchCoordinates($ocationIds)
    {
        $result = [];
        
        if (empty($ocationIds) || !is_array($ocationIds)) {
            return $result;
        }

        foreach ($ocationIds as $ocationId) {
            $result[$ocationId] = self::getCoordinates($ocationId);
        }

        return $result;
    }

    /**
     * 获取教学点经纬度和地址（简化版，返回经纬度和地址）
     *
     * @param int $ocationId 教学点ID
     * @return array ['longitude' => float|null, 'latitude' => float|null, 'address' => string|null]
     */
    public static function getSimpleCoordinates($ocationId)
    {
        $result = self::getCoordinates($ocationId);
        return [
            'longitude' => $result['longitude'],
            'latitude' => $result['latitude'],
            'address' => $result['address']
        ];
    }

    /**
     * 检查经纬度是否有效
     * 
     * @param mixed $longitude 经度
     * @param mixed $latitude 纬度
     * @return bool
     */
    private static function isValidCoordinate($longitude, $latitude)
    {
        // 检查是否为空或无效值
        if (empty($longitude) || empty($latitude)) {
            return false;
        }

        // 检查是否为字符串形式的0
        if ($longitude === '0' || $longitude === '0.0' || $longitude === '0.00') {
            return false;
        }
        if ($latitude === '0' || $latitude === '0.0' || $latitude === '0.00') {
            return false;
        }

        // 转换为浮点数检查
        $lng = (float)$longitude;
        $lat = (float)$latitude;

        // 检查是否为0
        if ($lng == 0.0 || $lat == 0.0) {
            return false;
        }

        // 检查经纬度范围是否合理
        if ($lng < -180 || $lng > 180) {
            return false;
        }
        if ($lat < -90 || $lat > 90) {
            return false;
        }

        return true;
    }

    /**
     * 获取教学点层级结构信息
     * 
     * @param int $ocationId 教学点ID
     * @return array 包含主教学点、父教学点、子教学点的信息
     */
    public static function getOcationHierarchy($ocationId)
    {
        if (!$ocationId) {
            return [
                'main' => null,
                'parent' => null,
                'children' => []
            ];
        }

        // 获取主教学点
        $mainOcation = Db::name('ocation')->where('id', $ocationId)->find();
        if (!$mainOcation) {
            return [
                'main' => null,
                'parent' => null,
                'children' => []
            ];
        }

        // 获取父教学点
        $parentOcation = null;
        if (!empty($mainOcation['parent']) && $mainOcation['parent'] > 0) {
            $parentOcation = Db::name('ocation')->where('id', $mainOcation['parent'])->find();
        }

        // 获取子教学点
        $childrenOcations = Db::name('ocation')
            ->where('parent', $ocationId)
            ->order('id ASC')
            ->select();

        return [
            'main' => $mainOcation,
            'parent' => $parentOcation,
            'children' => $childrenOcations ?: []
        ];
    }

    /**
     * 获取教学点的完整坐标信息（包含层级信息）
     * 
     * @param int $ocationId 教学点ID
     * @return array 包含坐标和层级信息
     */
    public static function getFullCoordinateInfo($ocationId)
    {
        $coordinates = self::getCoordinates($ocationId);
        $hierarchy = self::getOcationHierarchy($ocationId);

        return [
            'ocation_id' => $ocationId,
            'coordinates' => $coordinates,
            'hierarchy' => $hierarchy,
            'has_coordinates' => $coordinates['longitude'] !== null && $coordinates['latitude'] !== null
        ];
    }

    /**
     * 计算两个坐标点之间的距离（单位：公里）
     * 
     * @param float $lat1 第一个点的纬度
     * @param float $lng1 第一个点的经度
     * @param float $lat2 第二个点的纬度
     * @param float $lng2 第二个点的经度
     * @return float 距离（公里）
     */
    public static function calculateDistance($lat1, $lng1, $lat2, $lng2)
    {
        $earthRadius = 6371; // 地球半径（公里）

        $lat1Rad = deg2rad($lat1);
        $lng1Rad = deg2rad($lng1);
        $lat2Rad = deg2rad($lat2);
        $lng2Rad = deg2rad($lng2);

        $deltaLat = $lat2Rad - $lat1Rad;
        $deltaLng = $lng2Rad - $lng1Rad;

        $a = sin($deltaLat / 2) * sin($deltaLat / 2) +
             cos($lat1Rad) * cos($lat2Rad) *
             sin($deltaLng / 2) * sin($deltaLng / 2);

        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

        return $earthRadius * $c;
    }

    /**
     * 根据用户位置获取最近的教学点坐标
     * 
     * @param array $ocationIds 教学点ID数组
     * @param float $userLat 用户纬度
     * @param float $userLng 用户经度
     * @return array 按距离排序的教学点坐标信息
     */
    public static function getNearestOcations($ocationIds, $userLat, $userLng)
    {
        $coordinates = self::getBatchCoordinates($ocationIds);
        $result = [];

        foreach ($coordinates as $ocationId => $coord) {
            if ($coord['longitude'] !== null && $coord['latitude'] !== null) {
                $distance = self::calculateDistance(
                    $userLat, $userLng, 
                    $coord['latitude'], $coord['longitude']
                );
                
                $result[] = [
                    'ocation_id' => $ocationId,
                    'coordinates' => $coord,
                    'distance' => round($distance, 2)
                ];
            }
        }

        // 按距离排序
        usort($result, function($a, $b) {
            return $a['distance'] <=> $b['distance'];
        });

        return $result;
    }

    /**
     * 通过经纬度获取详细地址信息（调用百度地图API）
     *
     * @param float $longitude 经度
     * @param float $latitude 纬度
     * @return array 地址信息
     */
    public static function getAddressByCoordinates($longitude, $latitude)
    {
        if (!$longitude || !$latitude) {
            return [
                'success' => false,
                'message' => '经纬度参数无效',
                'data' => null
            ];
        }

        // 获取百度地图API配置（从ai配置文件中获取）
        $aiConfig = config('ai');
        $baiduConfig = $aiConfig['baidu_map'] ?? [];

        if (!$baiduConfig) {
            $baiduConfig = [
                'api_key_server' => 'your_baidu_map_api_key_here' // 默认配置
            ];
        }

        // 优先使用服务端API密钥
        $apiKey = $baiduConfig['api_key_server'] ?? $baiduConfig['api_key'] ?? '';

        if (empty($apiKey) || $apiKey === 'your_baidu_map_api_key_here') {
            return [
                'success' => false,
                'message' => '百度地图API密钥未配置',
                'data' => null
            ];
        }

        // 百度地图逆地理编码API URL
        $apiUrl = $baiduConfig['api_urls']['reverse_geocoding'] ?? 'https://api.map.baidu.com/reverse_geocoding/v3/';

        // 获取默认请求参数
        $defaultParams = $baiduConfig['default_params'] ?? [
            'output' => 'json',
            'coordtype' => 'wgs84ll',
            'extensions_poi' => 1,
            'extensions_road' => true,
            'extensions_town' => true
        ];

        $params = array_merge($defaultParams, [
            'ak' => $apiKey,
            'location' => $latitude . ',' . $longitude,
        ]);

        $requestUrl = $apiUrl . '?' . http_build_query($params);

        try {
            // 获取请求配置
            $requestConfig = $baiduConfig['request_config'] ?? [
                'timeout' => 10,
                'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'ssl_verify' => false
            ];

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $requestUrl);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, $requestConfig['timeout']);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $requestConfig['ssl_verify']);
            curl_setopt($ch, CURLOPT_USERAGENT, $requestConfig['user_agent']);

            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $error = curl_error($ch);
            curl_close($ch);

            if ($error) {
                return [
                    'success' => false,
                    'message' => 'cURL错误: ' . $error,
                    'data' => null
                ];
            }

            if ($httpCode !== 200) {
                return [
                    'success' => false,
                    'message' => 'API请求失败，HTTP状态码: ' . $httpCode,
                    'data' => null
                ];
            }

            $result = json_decode($response, true);

            if (!$result || $result['status'] !== 0) {
                return [
                    'success' => false,
                    'message' => '百度地图API返回错误: ' . ($result['message'] ?? '未知错误'),
                    'data' => null
                ];
            }

            // 解析地址信息
            $addressInfo = self::parseBaiduAddressResult($result['result']);

            return [
                'success' => true,
                'message' => '地址获取成功',
                'data' => $addressInfo
            ];

        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => '获取地址异常: ' . $e->getMessage(),
                'data' => null
            ];
        }
    }

    /**
     * 解析百度地图API返回的地址结果
     *
     * @param array $result 百度地图API返回的result部分
     * @return array 格式化的地址信息
     */
    private static function parseBaiduAddressResult($result)
    {
        $addressComponent = $result['addressComponent'] ?? [];
        $formattedAddress = $result['formatted_address'] ?? '';
        $pois = $result['pois'] ?? [];
        $roads = $result['roads'] ?? [];

        // 基本地址信息
        $addressInfo = [
            'formatted_address' => $formattedAddress,
            'province' => $addressComponent['province'] ?? '',
            'city' => $addressComponent['city'] ?? '',
            'district' => $addressComponent['district'] ?? '',
            'street' => $addressComponent['street'] ?? '',
            'street_number' => $addressComponent['street_number'] ?? '',
            'country' => $addressComponent['country'] ?? '中国',
            'country_code' => $addressComponent['country_code'] ?? 0,
            'adcode' => $addressComponent['adcode'] ?? '',
        ];

        // 附近POI信息（兴趣点）
        $nearbyPois = [];
        foreach (array_slice($pois, 0, 5) as $poi) { // 只取前5个POI
            $nearbyPois[] = [
                'name' => $poi['name'] ?? '',
                'address' => $poi['addr'] ?? '',
                'distance' => $poi['distance'] ?? 0,
                'direction' => $poi['direction'] ?? '',
                'tag' => $poi['tag'] ?? '',
                'tel' => $poi['tel'] ?? ''
            ];
        }

        // 附近道路信息
        $nearbyRoads = [];
        foreach (array_slice($roads, 0, 3) as $road) { // 只取前3条道路
            $nearbyRoads[] = [
                'name' => $road['name'] ?? '',
                'distance' => $road['distance'] ?? 0,
                'direction' => $road['direction'] ?? ''
            ];
        }

        $addressInfo['nearby_pois'] = $nearbyPois;
        $addressInfo['nearby_roads'] = $nearbyRoads;

        return $addressInfo;
    }

    /**
     * 获取教学点的完整位置信息（经纬度 + 地址）
     *
     * @param int $ocationId 教学点ID
     * @return array 包含经纬度和地址信息
     */
    public static function getLocationInfo($ocationId)
    {
        // 获取经纬度
        $coordinates = self::getCoordinates($ocationId);

        $result = [
            'ocation_id' => $ocationId,
            'coordinates' => $coordinates,
            'address_info' => null,
            'has_location' => false
        ];

        // 如果有经纬度，获取地址信息
        if ($coordinates['longitude'] && $coordinates['latitude']) {
            $addressResult = self::getAddressByCoordinates($coordinates['longitude'], $coordinates['latitude']);

            $result['address_info'] = $addressResult;
            $result['has_location'] = $addressResult['success'];
        }

        return $result;
    }

    /**
     * 批量获取多个教学点的完整位置信息
     *
     * @param array $ocationIds 教学点ID数组
     * @param bool $withDelay 是否添加延迟（避免API调用过于频繁）
     * @return array 格式：[ocation_id => location_info, ...]
     */
    public static function getBatchLocationInfo($ocationIds, $withDelay = true)
    {
        $result = [];

        if (empty($ocationIds) || !is_array($ocationIds)) {
            return $result;
        }

        foreach ($ocationIds as $ocationId) {
            $result[$ocationId] = self::getLocationInfo($ocationId);

            // 添加延迟，避免API调用过于频繁
            if ($withDelay) {
                usleep(100000); // 0.1秒延迟
            }
        }

        return $result;
    }

    /**
     * 格式化地址信息为可读字符串
     *
     * @param array $addressInfo 地址信息数组
     * @return string 格式化的地址字符串
     */
    public static function formatAddressString($addressInfo)
    {
        if (!$addressInfo || !is_array($addressInfo)) {
            return '';
        }

        $parts = [];

        // 基本地址
        if (!empty($addressInfo['formatted_address'])) {
            $parts[] = $addressInfo['formatted_address'];
        }

        // 附近POI
        if (!empty($addressInfo['nearby_pois'])) {
            $poiNames = [];
            foreach (array_slice($addressInfo['nearby_pois'], 0, 3) as $poi) {
                if (!empty($poi['name'])) {
                    $poiNames[] = $poi['name'];
                }
            }
            if (!empty($poiNames)) {
                $parts[] = '附近：' . implode('、', $poiNames);
            }
        }

        return implode('，', $parts);
    }

    /**
     * 递归查找有效的子教学点（包括子教学点的子教学点）
     *
     * @param int $parentId 父教学点ID
     * @return array|null 返回第一个找到的有效教学点，如果没有找到返回null
     */
    private static function findValidChildOcation($parentId)
    {
        // 获取所有直接子教学点
        $childOcations = Db::name('ocation')
            ->where('pid', $parentId)
            ->select();

        if (empty($childOcations)) {
            return null;
        }

        // 遍历每个子教学点
        foreach ($childOcations as $childOcation) {
            // 检查当前子教学点是否有有效的经纬度
            if (self::isValidCoordinate($childOcation['longitude'], $childOcation['latitude'])) {
                return $childOcation;
            }

            // 如果当前子教学点没有有效经纬度，递归查找它的子教学点
            $validGrandChild = self::findValidChildOcation($childOcation['id']);
            if ($validGrandChild) {
                return $validGrandChild;
            }
        }

        return null;
    }
}
